home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / genmix1b.zip / GENMIX / SRC / PORTWAVE.C < prev   
C/C++ Source or Header  |  1995-04-15  |  11KB  |  501 lines

  1. /* -------- PORTWAVE.C -- Low level sound output
  2.  */
  3.  
  4. #include "port.h"
  5.  
  6. #if iswin
  7.  
  8. #define inifile        "portwave.ini"
  9.  
  10. /*
  11.     Private profile string format:
  12.  
  13.     [ manu=[manuid] prod=[prodid] #[num] ]
  14.     name=            [prodname]
  15.     version=        [verhi].[verlo]
  16.     whatversion=    [ all thishi thishilo ]
  17.     8bit11khzmono=    [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  18.     8bit11khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  19.     8bit22khzmono=    [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  20.     8bit22khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  21.     8bit44khzmono=    [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  22.     8bit44khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  23.     16bit11khzmono= [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  24.     16bit11khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  25.     16bit22khzmono=  [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  26.     16bit22khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  27.     16bit44khzmono=  [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  28.     16bit44khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
  29. */
  30.  
  31. static short        waveinited = 0;
  32. static long            wavedatarate;
  33. static short        wavesamplesize;
  34. static short        numplaying;
  35. static short        curplaying;
  36. static short        nextplay;
  37. static short        usegetpos;
  38. static long            blocknumsamp;
  39. static PWAVEHDR        pbuf[16];
  40. static HANDLE        hbuf[16];
  41.        UINT            outdev;
  42. static HWAVEOUT        hwo;
  43. static int            playahead;
  44. static int            numblocks;
  45. static int            blocksize;
  46. static int            immremix;
  47.  
  48. static void sounderror(MMRESULT err, short num)
  49. {
  50.     int res;
  51.     char msg[256], errmsg[128];
  52.     
  53.     waveOutGetErrorText(err, (LPTSTR)errmsg, 128); 
  54.     sprintf(msg, "Sound Error %d:\n%s [%d]\n\n"
  55.             "Select OK to continue, Cancel to abort.",
  56.             err, errmsg, num);
  57.     res = MessageBox(NULL, msg, "Sound Error", MB_TASKMODAL|
  58.         MB_ICONEXCLAMATION|MB_OKCANCEL);
  59.     if (res==IDCANCEL) portFatalError(badmem, num);
  60.     return;
  61. }
  62.  
  63. static void soundwaitall(void)
  64. {
  65.     short    i;
  66.     short    done;
  67.  
  68.     do {
  69.         done = 1;
  70.         for (i=0; i<numblocks; i++)
  71.             if (!(pbuf[i]->dwFlags & WHDR_DONE)) done = 0;
  72.     } while (!done);
  73.     return;
  74. }
  75.  
  76. void CALLBACK soundcallback(HWAVEOUT hwaveout, UINT wmsg, 
  77.         DWORD dwinst, PWAVEHDR pwhcur, DWORD param2)
  78. {
  79.     int    i;
  80.  
  81.     if (wmsg != WOM_DONE) return;
  82.  
  83.     // locate block
  84.     for (i=0; i<numblocks; i++)
  85.         if (pbuf[i] == pwhcur) break;
  86.     if (i >= numblocks) return;;
  87.  
  88.     // advance ring buffer control pointers
  89.     numplaying--;
  90.     curplaying = i + 1;
  91.     if (curplaying >= numblocks) curplaying = 0;
  92.  
  93.     // start timing next packet
  94.     if (numplaying) 
  95.         pbuf[curplaying]->dwUser = timeGetTime();
  96.  
  97.     return;
  98. }                
  99.  
  100. char    drivername[32];
  101.  
  102. rescode    waveOpen(waveRate rate, waveBits bits, waveSpeak speak,
  103.             int *pblocksiz, int *pahead, int *premix)
  104. {
  105.     PCMWAVEFORMAT    wf;
  106.     MMRESULT        res;
  107.     UINT            idev;
  108.     int                i;
  109.     WAVEOUTCAPS        woc;
  110.  
  111.     if (waveinited) return 0;
  112.     
  113.     wavesamplesize = (short) bits * (short) speak;
  114.     wavedatarate = waveRateBase * (long) rate;
  115.    
  116.     // open output device
  117.     wf.wf.wFormatTag = WAVE_FORMAT_PCM;
  118.     wf.wf.nChannels = (short) speak;
  119.     wf.wf.nSamplesPerSec = wavedatarate;
  120.     wf.wf.nAvgBytesPerSec = wavedatarate * (long) wavesamplesize;
  121.     wf.wBitsPerSample = (short) bits * 8;
  122.     wf.wf.nBlockAlign = wavesamplesize;
  123.    
  124.         
  125.     // try all available output devices
  126.    idev=waveOutGetNumDevs();
  127.    outdev = 0;
  128.    while (outdev<idev) {
  129.            #if WINVER >= 0x0400
  130.         if (!waveOutOpen(&hwo, outdev, (WAVEFORMATEX*) &wf,
  131.             (DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
  132.         #else
  133.         if (!waveOutOpen(&hwo, outdev, (WAVEFORMAT*) &wf,
  134.             (DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
  135.         #endif
  136.         // shut off any playing sound and try again
  137.         if (outdev == 0)
  138.         {
  139.             sndPlaySound(NULL, 0);
  140.             #if WINVER >= 0x0400
  141.             if (!waveOutOpen(&hwo, outdev, (WAVEFORMATEX*) &wf, 
  142.                     (DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
  143.             #else
  144.             if (!waveOutOpen(&hwo, outdev, (WAVEFORMAT*) &wf, 
  145.                     (DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
  146.             #endif
  147.         }
  148.         outdev++;
  149.     }
  150.     if (idev==outdev) {
  151.         // try using wave mapper
  152.         outdev = WAVE_MAPPER;
  153.         #if WINVER >= 0x0400
  154.         res = waveOutOpen(&hwo, WAVE_MAPPER, (WAVEFORMATEX*) &wf, 
  155.                 (DWORD)soundcallback, 0, CALLBACK_FUNCTION);
  156.         #else
  157.         res = waveOutOpen(&hwo, WAVE_MAPPER, (WAVEFORMAT*) &wf, 
  158.                 (DWORD)soundcallback, 0, CALLBACK_FUNCTION);
  159.         #endif
  160.         if (!res) {
  161.             // get real output device number
  162.             res = waveOutGetID(hwo, &outdev);
  163.             if (res) {
  164.                 sounderror(res, 0);
  165.                 return 1;
  166.             }
  167.         }
  168.         else {
  169.             sounderror(res, 1);
  170.             return 1;
  171.         }
  172.     }
  173.     
  174.     // reset sound device
  175.     res = waveOutReset(hwo);
  176.     if (res) {
  177.         sounderror(res, 2);
  178.         return 1;
  179.     }
  180.  
  181.     {
  182.         char    formatstr[32];
  183.         char    verstr[16];
  184.         char    vermatchstr[8];
  185.         char    datastr[32];
  186.         int        num, verhi, verlo;
  187.         char    drvname[32];
  188.  
  189.         res = waveOutGetDevCaps(outdev, &woc, sizeof(WAVEOUTCAPS));
  190.         if (res) {
  191.             sounderror(res, 3);
  192.             return 1;
  193.         }
  194.         num = 0;
  195.         do {
  196.             sprintf(drivername, "manu=%x prod=%x #%d", (int)woc.wMid, 
  197.                 (int)woc.wPid, num);
  198.             GetPrivateProfileString(drivername, "version", "", verstr,
  199.                 sizeof(verstr),inifile);
  200.             if (verstr[0]) 
  201.             {
  202.                 if (2 != sscanf(verstr, "%x.%x", &verhi, &verlo))
  203.                 {
  204.                     sounderror(0, 4);
  205.                     return 1;
  206.                 }
  207.                 GetPrivateProfileString(drivername, "whatversion", "all",
  208.                     vermatchstr, sizeof(vermatchstr), inifile);
  209.                 if (strcmp("all", vermatchstr)) break;
  210.                 if (strcmp("thishi", vermatchstr) == 0 && 
  211.                     verhi == HIBYTE(woc.vDriverVersion) ) break;
  212.                 if (strcmp("thishilo", vermatchstr) == 0 &&
  213.                     verhi == HIBYTE(woc.vDriverVersion) &&
  214.                     verlo == LOBYTE(woc.vDriverVersion) ) break;
  215.                 num++;
  216.             }
  217.             else break;    
  218.         } while (1);
  219.         if (!verstr[0]) strcpy(drvname, "default");
  220.         else strcpy(drvname, drivername);
  221.         sprintf(formatstr, "%dbit%dkhz%s", bits==waveBits8 ? 8 :16,
  222.             11 * (int)rate, speak==waveSpeakMono ? "mono" : "stereo");
  223.         GetPrivateProfileString(drvname, formatstr, "", datastr,
  224.             sizeof(datastr), inifile); 
  225.         if (4 != sscanf(datastr, "%d %d %d %d", &blocksize, &playahead, 
  226.             &immremix, &usegetpos))
  227.         {
  228.             MessageBox(NULL, "Please copy the file PORTWAVE.INI\nto your Windows directory.",
  229.                 "Fatal Error", MB_TASKMODAL|MB_ICONEXCLAMATION|MB_OK);
  230.             sounderror(0, 7);
  231.             return 1;
  232.         }
  233.     }
  234.  
  235.     // allocate output buffers
  236.     numblocks = playahead + 1;
  237.     blocknumsamp = blocksize / wavesamplesize;
  238.  
  239.     // initialize output headers
  240.     for (i=0; i<numblocks; i++) {
  241.         hbuf[i] = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, 
  242.                     sizeof(WAVEHDR) + blocksize);
  243.         pbuf[i] = (PWAVEHDR) GlobalLock(hbuf[i]); 
  244.         if (!pbuf[i]) return 1;
  245.         pbuf[i]->dwBufferLength = blocksize;
  246.         pbuf[i]->dwBytesRecorded = blocksize;
  247.         pbuf[i]->dwUser = 0;
  248.         pbuf[i]->dwFlags = WHDR_DONE;
  249.         pbuf[i]->dwLoops = 0;
  250.         pbuf[i]->lpData = (LPSTR)(pbuf[i]) + sizeof(WAVEHDR);
  251.         res = waveOutPrepareHeader(hwo, pbuf[i], sizeof(WAVEHDR));
  252.         if (res) {
  253.             sounderror(res, 3);
  254.             return 1;
  255.         }
  256.     }
  257.     
  258.     // initialize ring buffer
  259.     waveinited = 1;
  260.     numplaying = 0;
  261.     curplaying = 0;
  262.     nextplay = -1;
  263.  
  264.     *pblocksiz = blocksize / wavesamplesize;
  265.     *pahead = playahead;
  266.     *premix = immremix;
  267.  
  268.     return 0;
  269. }
  270.  
  271. rescode waveClose()
  272. {
  273.     int            i;
  274.     MMRESULT    res;
  275.  
  276.     if (!waveinited) return 0;
  277.  
  278.     // reset wave device prior to closing
  279.     res = waveOutReset(hwo);
  280.     if (res) {
  281.         sounderror(res, 9);
  282.         return 1;
  283.     }
  284.     // sit and spin while buffer clears
  285.     soundwaitall();
  286.     
  287.     // dispose of output headers
  288.     for (i=0; i<numblocks; i++) {
  289.         res = waveOutUnprepareHeader(hwo, pbuf[i], sizeof(WAVEHDR));
  290.         if (res) {
  291.             sounderror(res, 5);
  292.             return 1;
  293.         }
  294.         GlobalUnlock(hbuf[i]);
  295.         GlobalFree(hbuf[i]);
  296.     }
  297.  
  298.     // close output device
  299.     res = waveOutClose(hwo);
  300.     if (res) {
  301.         sounderror(res, 4);
  302.         return 1;
  303.     }
  304.     
  305.     waveinited = 0;
  306.     
  307.     return 0;
  308. }
  309.  
  310. rescode waveReset()
  311. {
  312.     MMRESULT    res;
  313.     
  314.     if (!waveinited) return 1;
  315.     
  316.     // reset the device
  317.     res = waveOutReset(hwo);
  318.     if (res) {
  319.         sounderror(res, 6);
  320.         return 1;
  321.     }
  322.     // sit and spin until the output buffer is empty
  323.     soundwaitall();
  324.         
  325.     return 0;
  326. }
  327.  
  328. rescode waveGetPlayPtr(pmem *pptr)
  329. {
  330.     if (!waveinited) return 1;
  331.     if (nextplay != -1) portFatalError(badlog, 0);
  332.     if (numplaying >= numblocks) portFatalError(badlog,0);
  333.     // return a pointer to the buffer after the last one playing    
  334.     nextplay = curplaying + numplaying;
  335.     if (nextplay >= numblocks) nextplay -= numblocks;
  336.  
  337.     *pptr = pbuf[nextplay]->lpData;
  338.     return 0;
  339. }
  340.  
  341. rescode wavePlay()
  342. {
  343.     MMRESULT    res;
  344.     
  345.     if (!waveinited) return 1;
  346.     if (nextplay == -1) portFatalError(badlog, 0);
  347.  
  348.     // start timing this block if it's going out immediatly    
  349.     if (!numplaying) { 
  350.         curplaying = nextplay;
  351.         pbuf[nextplay]->dwUser = timeGetTime();
  352.         waveOutPause(hwo);
  353.     }
  354.     
  355.     // play sound packet
  356.     res = waveOutWrite(hwo, pbuf[nextplay], sizeof(WAVEHDR));
  357.     if (res) {
  358.         sounderror(res, 7);
  359.         return 1;
  360.     }
  361.     if (!numplaying) waveOutRestart(hwo);
  362.     numplaying++;
  363.     nextplay = -1;
  364.     
  365.     return 0;
  366. }
  367.  
  368. rescode waveGetSampleCount(long *psize)
  369. {
  370.     DWORD            elapsed;
  371.     long            sampplaying;
  372.     long            samppacket;
  373.     static long        np,cp;
  374.     MMRESULT        res;
  375.     MMTIME            mmt;
  376.     
  377.     if (!waveinited) return 1;
  378.  
  379.         np = numplaying;
  380.         cp = curplaying;
  381.  
  382.         // get the total of all full or partial packets playing
  383.         sampplaying = np * blocknumsamp;
  384.     
  385.         // subtract a fractional packet, if any
  386.         if (np) {
  387.             if (usegetpos) 
  388.             {
  389.                 mmt.wType = TIME_SAMPLES;
  390.                 res = waveOutGetPosition(hwo, &mmt, sizeof(mmt));
  391.                 if (res) sounderror(res, 8);
  392.                 if (mmt.wType != TIME_SAMPLES) sounderror(res, 9);
  393.                 samppacket = mmt.u.sample;
  394.             }
  395.             else {
  396.                 // measure number of samples that have played
  397.                 elapsed = timeGetTime() - pbuf[cp]->dwUser;
  398.                 samppacket = (long)elapsed * (long)wavedatarate / 1000L;
  399.             }
  400.  
  401.             if (samppacket < 0) samppacket = 0;
  402.             else if (samppacket >= blocknumsamp) samppacket = blocknumsamp-1;
  403.             sampplaying -= samppacket;
  404.         }
  405.         *psize = sampplaying;
  406.     return 0;
  407. }
  408.  
  409. rescode waveGetVolume(short *pvol)
  410. {
  411.     DWORD        v;
  412.     MMRESULT    res;
  413.     
  414.     if (!waveinited) return 1;
  415.  
  416.     #if WINVER >= 0x0400
  417.     res = waveOutGetVolume(hwo, &v);
  418.     #else
  419.     res = waveOutGetVolume(outdev, &v);
  420.     #endif
  421.     // ignore error if function not supported
  422.     if (res==MMSYSERR_NOTSUPPORTED) {
  423.         *pvol = 7;
  424.         return 0;
  425.     }
  426.     if (res) {
  427.         sounderror(res, 10);
  428.         return 1;
  429.     }
  430.     // convert to 0..7 scale
  431.     v = LOWORD(v);
  432.     v = v * 7 / 0xFFFF;
  433.     *pvol = (int) v;
  434.     return 0;
  435. }
  436.  
  437. rescode waveSetVolume(short newvol)
  438. {
  439.     DWORD        v;
  440.     MMRESULT    res;
  441.     
  442.     if (!waveinited) return 1;
  443.  
  444.     // calculate a volume in the range 0..FFFF
  445.     v = (DWORD)newvol * 0xFFFF / 7;
  446.     v &= 0xFFFF;
  447.     // or in right channel volume
  448.     v |= (v<<16);
  449.     #if WINVER >= 0x0400
  450.     res = waveOutSetVolume(hwo, v);
  451.     #else
  452.     res = waveOutSetVolume(outdev, v);
  453.     #endif
  454.     // ignore error if function not supported
  455.     if (res==MMSYSERR_NOTSUPPORTED) return 0;
  456.     if (res) {
  457.         sounderror(res, 8);
  458.         return 1;
  459.     }
  460.     return 0;
  461. }
  462.  
  463. #endif    // iswin
  464.  
  465. #if ismac || isppc
  466.  
  467. rescode    waveOpen(waveRate rate, waveBits bits, waveSpeak speak)
  468. {
  469. }
  470.  
  471. rescode waveClose()
  472. {
  473. }
  474.  
  475. rescode waveReset()
  476. {
  477. }
  478.  
  479. rescode waveGetPlayPtr(pmem *pptr)
  480. {
  481. }
  482.  
  483. rescode wavePlay()
  484. {
  485. }
  486.  
  487. rescode waveGetSampleCount(long *psize)
  488. {
  489. }
  490.  
  491. rescode waveGetVolume(short *pvol)
  492. {
  493. }
  494.  
  495. rescode waveSetVolume(short newvol)
  496. {
  497. }
  498.  
  499.  
  500. #endif    // ismac || isppc
  501.